Skip to content

feat(agents): Option B — _BackendProtocol in langchain, backend on AgentRuntime#37928

Open
Sydney Runkle (sydney-runkle) wants to merge 1 commit into
sr/agent-runtimefrom
sr/agent-runtime-option-b
Open

feat(agents): Option B — _BackendProtocol in langchain, backend on AgentRuntime#37928
Sydney Runkle (sydney-runkle) wants to merge 1 commit into
sr/agent-runtimefrom
sr/agent-runtime-option-b

Conversation

@sydney-runkle
Copy link
Copy Markdown
Collaborator

Alternative to the approach in this branch — moves the backend protocol definition into langchain so `AgentRuntime.backend` is properly typed at the langchain layer.

```python
class _BackendProtocol(Protocol): # private to langchain
def read(self, path: str) -> str: ...
def write(self, path: str, content: str) -> Any: ...
def ls(self, path: str) -> Any: ...
def download_files(self, paths: list[str]) -> Any: ...
async def aread(self, path: str) -> str: ...
async def awrite(self, path: str, content: str) -> Any: ...
async def als(self, path: str) -> Any: ...
async def adownload_files(self, paths: list[str]) -> Any: ...

DataClass
class AgentRuntime(Runtime[ContextT]):
...
backend: _BackendProtocol | None = None # properly typed

def create_agent(model, tools=None, *, backend: _BackendProtocol | None = None, ...): ...
```

vs. Option A (current branch)

Option A Option B
backend typing in langchain object | None (loose) _BackendProtocol | None (typed)
deepagents subclass AgentRuntime(LCAgentRuntime) none
BackendMiddleware public, required not needed
BackendProtocol owner deepagents langchain (private)
runtime.backend in DA hooks non-optional, typed optional (None-guard needed)

…entRuntime

- _BackendProtocol: private Protocol with core backend methods (read/write/ls etc.)
- AgentRuntime.backend: _BackendProtocol | None — typed at the langchain layer
- create_agent accepts backend= and threads it into AgentRuntime at dispatch time
- No AgentRuntime subclass or BackendMiddleware needed in subpackages
@github-actions github-actions Bot added feature For PRs that implement a new feature; NOT A FEATURE REQUEST internal langchain `langchain` package issues & PRs size: XS < 50 LOC labels Jun 5, 2026
Copy link
Copy Markdown
Contributor

@open-swe open-swe Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Open SWE Review found 1 potential issue.

View Open SWE trace

model_settings: dict[str, Any] = field(default_factory=dict)
"""Additional model-specific settings."""

backend: _BackendProtocol | None = field(default=None)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Backend cannot be overridden on ModelRequest

Adding AgentRuntime.backend makes backend part of the runtime state carried by model middleware, but ModelRequest.override() still only treats model/system_prompt/tool_choice/tools/response_format/model_settings as runtime fields. A middleware that tries to replace or clear the backend for a nested handler call via request.override(backend=...) will route backend to dataclasses.replace(self, ...) on ModelRequest, which raises TypeError: ModelRequest.__init__() got an unexpected keyword argument 'backend' at runtime. Include backend in the override typed dict and _runtime_fields (and optionally expose a backend property) so backend behaves like the other AgentRuntime fields.

(Refers to line 120)


Was this helpful? React with 👍 or 👎 to provide feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature For PRs that implement a new feature; NOT A FEATURE REQUEST internal langchain `langchain` package issues & PRs size: XS < 50 LOC

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant